package com.duoec.magichour.core.web.interceptor;

import com.duoec.magichour.core.annotation.Access;
import com.duoec.magichour.core.exceptions.BusinessException;
import com.duoec.magichour.core.utils.CookieUtils;
import com.duoec.magichour.core.web.BaseWebController;
import com.duoec.magichour.core.web.MyModelAndView;
import com.duoec.magichour.core.web.UserInfoHolder;
import com.duoec.magichour.dto.BaseResponse;
import com.duoec.magichour.dto.UserInfo;
import com.duoec.magichour.enums.RoleEnum;
import com.duoec.magichour.service.AuthorizeService;
import com.duoec.magichour.service.SiteService;
import com.google.common.base.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * Created by ycoe on 17/6/25.
 */
public class HttpInterceptor extends HandlerInterceptorAdapter {

    private static final String TEST_TOKEN_USER_STR = "test_token_user_";
    private static final String FORBID_MESSAGE = "权限不足！";
    public static final String AUTH_TOKEN = "auth-token";

    @Autowired
    private AuthorizeService authorizeService;

    @Autowired
    private SiteService siteService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setCharacterEncoding("UTF-8");

        //初始化授权用户
        UserInfo userInfo = initUserInfo(request);

        MyModelAndView view = null;
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Object bean = handlerMethod.getBean();
        if (bean instanceof BaseWebController) {
            BaseWebController controller = (BaseWebController) bean;
            view = new MyModelAndView();
            controller.setView(view);
        }

        //检查用户权限，如果权限不足，会抛个异常
        checkAccess(userInfo, (HandlerMethod) handler);

        if (bean instanceof BaseWebController) {
            //加载常用配置
            Map<String, Object> vars = siteService.commonVars();
            if (vars != null) {
                vars.forEach(view::addData);
            }
        }

        return true;
    }

    private void checkAccess(UserInfo userInfo, HandlerMethod handler) {
        Method method = handler.getMethod();
        Access access = method.getAnnotation(Access.class);
        if (access == null) {
            return;
        }

        //有限制
        if (userInfo == null) {
            throw new BusinessException(BaseResponse.CODE_FORBID, FORBID_MESSAGE);
        }

        List<RoleEnum> roleList = userInfo.getRoleList();
        if (roleList == null || roleList.isEmpty()) {
            throw new BusinessException(BaseResponse.CODE_FORBID, FORBID_MESSAGE);
        }
        if (roleList.contains(RoleEnum.ADMIN)) {
            //超级管理员
            return;
        }
        for (RoleEnum role : roleList) {
            if (access.value() == role) {
                return;
            }
        }
        throw new BusinessException(BaseResponse.CODE_FORBID, FORBID_MESSAGE);
    }

    private UserInfo initUserInfo(HttpServletRequest request) {
        String authToken = request.getHeader("auth-token");
        if (Strings.isNullOrEmpty(authToken)) {
            //尝试去cookies中取
            authToken = CookieUtils.getCookie(request, AUTH_TOKEN);
        }
        if (!Strings.isNullOrEmpty(authToken)) {
            // 如果有值，则尝试获取对应的用户
            UserInfo userInfo;
            if (authToken.startsWith(TEST_TOKEN_USER_STR)) {
                //测试账号
                String userIdStr = authToken.substring(TEST_TOKEN_USER_STR.length());
                userInfo = authorizeService.getUserInfo(Long.parseLong(userIdStr));
                if (userInfo != null) {
                    userInfo.setAuthorToken(authToken);
                }
            } else {
                //正常账号
                userInfo = authorizeService.get(authToken);
            }
            if (userInfo != null) {
                UserInfoHolder.set(userInfo);
            }
            return userInfo;
        }
        return null;
    }
}
